package com.baoxin.utils;

import org.apache.commons.beanutils.ConvertUtils;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: Rose
 * @Date: 2020/4/23 13:20
 * @version: 1.0.0
 */
@Transactional(rollbackOn = Exception.class)
@Repository
public class CustomDao {

    @PersistenceContext
    private EntityManager entityManager ;

    private static  final Logger log = LoggerFactory.getLogger(CustomDao.class);


    /**
     *
     *
     *
     * @param sql
     * @param params
     * @param clazz
     * @return
     */

    public List<?> queryForListEntity(String sql , Map<String,Object> params ,Class<?> clazz){
        NativeQueryImpl unwrap = createSQLQuery(sql,params);
        unwrap.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map<String,Object>> list = unwrap.list();
        if(clazz != null){
            List<Object> entityList = convert(clazz,list);
            return  entityList;
        }
        return  list;
    }

    /**
     *   分页查询
     *
     * @param sql  查询sql
     * @param params  查询参数
     * @param clazz  封装的实体bean
     * @param pageNum
     * @param pageSize 每页显示的条数
     * @return
     */
    public List<?> queryForListEntityByPage(String sql , Map<String,Object> params , Class<?> clazz, Integer pageNum , Integer pageSize){
        NativeQueryImpl unwrap = createSQLQuery(sql,params);
        unwrap.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        unwrap.setFirstResult(pageNum.intValue());
        unwrap.setMaxResults(pageSize.intValue());
        List<Map<String,Object>> list = unwrap.list();
        if(clazz != null){
            List<Object> entityList = convert(clazz,list);
            return  entityList;
        }
        return  list;
    }

    /**
     *   根据条件查询返回实体bean
     *
     * @param sql
     * @param params
     * @param clazz
     * @return
     */
    public List<?> queryForListBean(String sql , Map<String,Object> params ,Class<?> clazz){
        NativeQueryImpl unwrap = createSQLQuery(sql,params);
        unwrap.setResultTransformer(Transformers.aliasToBean(clazz));
        List<Object> list = unwrap.list();
        return  list;
    }

    /**
     *   根据条件查询返回实体bean 分页显示查询结果
     *
     * @param sql
     * @param params
     * @param clazz
     * @param pageNum
     * @param pageSize
     * @return
     */
    public List<?> queryForListBeanByPage(String sql , Map<String,Object> params ,Class<?> clazz , Integer pageNum , Integer pageSize){
        NativeQueryImpl unwrap = createSQLQuery(sql,params);
        unwrap.setResultTransformer(Transformers.aliasToBean(clazz));
        unwrap.setFirstResult(pageNum.intValue());
        unwrap.setMaxResults(pageSize.intValue());
        List<Object> list = unwrap.list();
        return  list;
    }

    /**
     *  获取记录数
     *
     * @param sql
     * @param params
     * @return
     */
    public Integer getCount(String sql , Map<String,Object> params){
        Query query = createQuery(sql, params);
        BigInteger singleResult = (BigInteger) query.getSingleResult();
        return singleResult.intValue();
    }

    /**
     *
     * @param sql
     * @param params
     * @return
     */
    public Query createQuery(String sql , Map<String,Object> params){
        Query nativeQuery = entityManager.createNativeQuery(sql);
        if(params != null){
            for (String key :  params.keySet()){
                nativeQuery.setParameter(key,params.get(key));
            }
        }
        return nativeQuery;
    }

    /**
     *
     * @param sql
     * @param params
     * @return
     */
    public NativeQueryImpl createSQLQuery(String sql , Map<String,Object> params){
        Query nativeQuery = entityManager.createNativeQuery(sql);
        NativeQueryImpl query = nativeQuery.unwrap(NativeQueryImpl.class);
        if(params != null){
            for (String key :  params.keySet()){
                query.setParameter(key,params.get(key));
            }
        }
        log.info(" 查询的sql = " + query.getQueryString());
        return query;
    }

    /**
     *  更新操作
     *
     * @param sql
     * @param params
     * @return
     */
    public Integer  updateSQL(String sql , Map<String,Object> params){
        Query query = createQuery(sql, params);
        return query.executeUpdate();
    }

    /**
     *  查询结果 返回list<Map>
     *
     *
     * @param sql
     * @param params
     * @return
     */
    public List<Map<String,Object>> queryForList(String sql , Map<String,Object> params){
        NativeQueryImpl sqlQuery = createSQLQuery(sql, params);
        sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map<String,Object>> list = sqlQuery.list();
        return list ;
    }



    /**
     *  Map 集合 转换为 Bean
     *
     * @param clazz
     * @param list
     * @return
     */
    private List<Object> convert(Class<?> clazz, List<Map<String, Object>> list) {
        // 判读 map 是否为空
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<Object>();
        }
        List<Object> result = new ArrayList<>();
        try {
            // 获取 类的描述信息
            PropertyDescriptor[] props = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
            // 遍历List 集合
            for (Map<String, Object> map : list) {
                // 获取 bean 的实例对象
                Object obj = clazz.newInstance();
                // 遍历 每一个Map 集合
                for (String key : map.keySet()) {
                    // 获取每个键
                    String attrName = key;
                    // 遍历 类的描述信息
                    for (PropertyDescriptor prop : props) {
                        // 给每个键去除 下划线
                        attrName = removeUnderLine(attrName);
                        // 去除下划线的键  和  类的属性 比较 是否相等
                        if (!attrName.equals(prop.getName())) {
                            continue;
                        }
                        //
                        Method method = prop.getWriteMethod();
                        // 获取每个键的值
                        Object value = map.get(key);
                        // 如果每个键的值 不为空，则进行填充
                        if (value != null) {
                            value = ConvertUtils.convert(value,prop.getPropertyType());
                        }
                        method.invoke(obj,value);
                    }
                }
                result.add(obj);
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            e.printStackTrace();
            throw new RuntimeException("数据转换错误");
        }
        return result;
    }


    /**
     *  去掉 数据库字段的空格并进行 驼峰转换
     * @param attrName
     * @return
     */
    private String removeUnderLine(String attrName) {
        //去掉数据库字段的下划线
        if(attrName.contains("_")) {
            // 用下划线进行切割
            String[] names = attrName.split("_");
            // 获取第一个 切割的值
            String firstPart = names[0];
            //
            String otherPart = "";
            for (int i = 1; i < names.length; i++) {
                // 将切割后的每段的内容的 首字母转大写
                String word = names[i].replaceFirst(names[i].substring(0, 1), names[i].substring(0, 1).toUpperCase());
                // 转换后进行拼接
                otherPart += word;
            }
            attrName = firstPart + otherPart;
        }
        return attrName;
    }


}
